﻿using Digitalmes.Events;
using Digitalmes.Model;
using Digitalmes.Models;
using Digitalmes.Parameter;
using Digitalmes.Signals;
using MediatR;
using Microsoft.Extensions.DependencyInjection;
using Nito.AsyncEx;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace Digitalmes.Services.Communication
{
    public abstract class BaseDriver :BaseService,  IDriver
    {
        protected  string _host;
        protected  int _port;
        protected  DriverTypeEnum _protocol;
        protected DriverStatus _status = DriverStatus.Disconnected;
        protected bool _isDisposed;
        protected CancellationTokenSource _cts;
        protected Task _pollingTask;

       
        protected DriverParameter Parameter { get; set; }   

        protected readonly object _lockObj = new object();

        public int MaxPackage { get; set; } = 19;

        // 心跳和轮询管理
        protected Timer _heartbeatTimer;

        protected int _heartbeatInterval = 5000;

        protected readonly Dictionary<string, (int interval, DateTime lastRead)> _pollingTags =
            new Dictionary<string, (int, DateTime)>();

        // 缓存管理
        protected readonly ConcurrentDictionary<string, object> _tagCache =
            new ConcurrentDictionary<string, object>();

        protected readonly ConcurrentDictionary<string, ISysTag> _variables = new();

        public string Host => _host;
        public int Port => _port;
        public DriverTypeEnum Protocol => _protocol;
        public DriverStatus Status => _status;

        public bool IsConnected => _status == DriverStatus.Connected;

        public List<ISysTag> Tags { get; set; }

        public string DriverName;

        public event EventHandler<DriverStatusChangedEventArgs> StatusChanged;

        public event EventHandler<TagValueChangedEventArgs> TagValueChanged;

        public event EventHandler<DriverErrorEventArgs> ErrorOccurred;

        public virtual IEnumerable<ISysTag> GetAllVariables()
        {
            return this._variables.Values.ToList();
        }

        public  readonly IMediator Mediator;
        protected BaseDriver(IServiceProvider provider):base(provider)
        {
            Mediator = GetService<IMediator>();
        }



        public async Task SendSignal(ISysTag tag)
        {
            
            if (tag.TagType == TagDefineEnum.Entry_Sign)
            {
                var entry = new EntrySignal() { SignalTag = tag };
                var result = await Mediator.Send(entry);
            }

            if (tag.TagType == TagDefineEnum.Archive_Sign)
            {
                var exit = new ExitSignal() { SignalTag = tag };
                var result = await Mediator.Send(exit);
            }
        }


        protected AsyncLock _mutex = new AsyncLock();   

       


        protected virtual void OnStatusChanged(DriverStatus oldStatus, DriverStatus newStatus)
        {
            StatusChanged?.Invoke(this, new DriverStatusChangedEventArgs(oldStatus, newStatus));
        }

        protected async Task SetStatus(DriverStatus newStatus)
        {
            if (_status == newStatus) return;

            var oldStatus = _status;
            _status = newStatus;
            OnStatusChanged(oldStatus, newStatus);

            // 状态变化处理
            if (newStatus == DriverStatus.Connected)
            {
                StartPolling();
            }
            else if (newStatus == DriverStatus.Disconnected ||
                     newStatus == DriverStatus.Error)
            {
                await StopHeartbeat();
                StopPolling();
            }
           
        }

        public virtual void RegisterForPolling(string tag, int intervalMs)
        {
            lock (_lockObj)
            {
                _pollingTags[tag] = (intervalMs, DateTime.MinValue);
            }
        }

        public virtual void UnregisterForPolling(string tag)
        {
            lock (_lockObj)
            {
                if (_pollingTags.ContainsKey(tag))
                {
                    _pollingTags.Remove(tag);
                }
            }
        }

        public virtual Task StartHeartbeat(int interval, string testAddress = null)
        {
            _heartbeatTimer?.Dispose();
            _heartbeatTimer = new Timer(HeartbeatCallback, null, interval, interval);
            return Task.CompletedTask;
        }

        public virtual Task StopHeartbeat()
        {
            _heartbeatTimer?.Dispose();
            _heartbeatTimer = null;
            return Task.CompletedTask;
        }

        protected virtual async void HeartbeatCallback(object state)
        {
            try
            {
                // 心跳检测 - 读取一个固定标签
                var result = await ReadValueAsync(new[] { "HeartbeatTag" });
                if (!result.Result.ContainsKey("HeartbeatTag") || result.Result["HeartbeatTag"] == null)
                {
                    await SetStatus(DriverStatus.Error);
                }
            }
            catch
            {
                await SetStatus(DriverStatus.Error);
            }
        }

        /// <summary>
        /// 订阅不成功,或者不支持订阅时,采用定时器轮询
        /// </summary>
        /// <returns></returns>
        protected virtual void StartPolling()
        {
            StopPolling();

            _cts = new CancellationTokenSource();
            _pollingTask = Task.Run(async () =>
            {
                while (!_cts.Token.IsCancellationRequested)
                {
                    try
                    {
                        await PollTagsAsync();
                        await Task.Delay(100, _cts.Token); // 基本轮询间隔
                    }
                    catch (OperationCanceledException)
                    {
                        // 任务取消
                        break;
                    }
                    catch (Exception ex)
                    {
                        // 记录错误
                        Console.WriteLine($"Polling error: {ex.Message}");
                        await SetStatus(DriverStatus.Error);
                        await Task.Delay(1000, _cts.Token);
                    }
                }
            }, _cts.Token);
        }

        /// <summary>
        /// 停止轮询 订阅不成功,或者不支持订阅时,采用定时器轮询
        /// </summary>
        /// <returns></returns>
        protected virtual void StopPolling()
        {
            _cts?.Cancel();
            _pollingTask?.Wait();
            _cts?.Dispose();
            _cts = null;
        }

        /// <summary>
        ///开始轮询 订阅不成功,或者不支持订阅时,采用定时器轮询
        /// </summary>
        /// <returns></returns>
        protected virtual async Task PollTagsAsync()
        {
            List<string> tagsToPoll = new List<string>();
            DateTime now = DateTime.Now;

            lock (_lockObj)
            {
                foreach (var kvp in _pollingTags)
                {
                    if ((now - kvp.Value.lastRead).TotalMilliseconds >= kvp.Value.interval)
                    {
                        tagsToPoll.Add(kvp.Key);
                        _pollingTags[kvp.Key] = (kvp.Value.interval, now);
                    }
                }
            }

            if (tagsToPoll.Count > 0)
            {
                // 将地址列表按每最大包分组
                var addressBatches = tagsToPoll
                    .Select((addr, index) => new { addr, index })
                    .GroupBy(x => x.index / MaxPackage, x => x.addr);

                foreach (var address in addressBatches)
                {
                    var results = await ReadValueAsync(address);
                    foreach (var result in results.Result)
                    {
                        TagValueChanged?.Invoke(this, new TagValueChangedEventArgs(result.Key, result.Value));
                    }
                }
            }
        }

        protected virtual void OnTagValueChanged(string tag, object value)
        {
            TagValueChanged?.Invoke(this, new TagValueChangedEventArgs(tag, value));
        }

        public virtual void Dispose()
        {
            if (_isDisposed) return;
            _isDisposed = true;
        }

        public abstract Task<ServiceResponse> ConnectAsync(DriverParameter para );

        public abstract Task<ServiceResponse> Disconnect();

        public abstract ServiceResponse AddVariable(ISysTag variable);

        public abstract ServiceResponse RemoveVariable(ISysTag variable);

        public abstract Task<ServiceResponse> ReadValueAsync(string address);

        public abstract Task<ServiceResponse> WriteValueAsync(string address, object value);

        public abstract Task<ServiceResponse<Dictionary<string, object>>> ReadValueAsync(IEnumerable<string> addresses);

        public abstract Task<ServiceResponse> WriteValueAsync(Dictionary<string, object> addressValuePairs);

        public virtual async ValueTask DisposeAsync()
        {
            await Disconnect();
            await StopHeartbeat();
            StopPolling();
        }
    }
}
